﻿package net.wangit.framework.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import net.wangit.context.ActionContext;
import net.wangit.framework.action.ActionConfigurationException;
import net.wangit.framework.config.Operator;
import net.wangit.framework.expression.Request2SessionExpression;
import net.wangit.jdbc.ColumnRow;
import net.wangit.jdbc.Table;
import net.wangit.jdbc.executable.AbstractColumnRow;
import net.wangit.jdbc.executable.DeleteRow;
import net.wangit.jdbc.executable.InsertRow;
import net.wangit.jdbc.executable.UpdateRow;
import net.wangit.jdbc.table.Column;
import net.wangit.jdbc.table.TableMeta;
import net.wangit.jdbc.table.TableMetaFactory;
import net.wangit.util.Checker;
import net.wangit.util.StringUtil;
import net.wangit.view.unit.UnitComponent;
import net.wangit.view.unit.UnitFactory;
import net.wangit.view.unit.util.UnitUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class ActionCommandUtil {

	private static final Log log = LogFactory
			.getLog(net.wangit.framework.interceptor.LoadTablesAI.class);

	public ActionCommandUtil() {
	}

	public static List<Table> load(ActionContext ac, String domain,
			String commandString) {
		String[][] commands;
		try {
			commands = StringUtil.split(commandString, ";", ",");
		} catch (Exception e) {
			log.error((new StringBuilder("ActionCommand format error: "))
					.append(commandString).toString());
			throw new ActionConfigurationException((new StringBuilder(
					"ActionCommand format error: ")).append(commandString)
					.toString(), e);
		}
		if (commands == null)
			return null;
		List<Table> tables = new ArrayList<Table>();
		for (int i = 0; i < commands.length; i++) {
			String[] command = commands[i];
			if (command.length < 2) {
				log.error("command length<2!");
				throw new ActionConfigurationException((new StringBuilder(
						"invaild Action command: ")).append(commandString)
						.toString());
			}
			String tableName = command[0];
			String sonTableName = null;
			String[][] linkedFields = (String[][]) null;
			if (tableName.indexOf("(") > 0 && tableName.endsWith(")")) {
				int index = tableName.indexOf("(");
				String temp = StringUtil.find(tableName, "(", ")");
				tableName = tableName.substring(0, index);
				index = temp.indexOf(":");
				if (index < 0) {
					log.error((new StringBuilder(
							"could not find son table in command: ")).append(
							commandString).toString());
					throw new ActionConfigurationException((new StringBuilder(
							"command format error: ")).append(commandString)
							.toString());
				}
				sonTableName = temp.substring(0, index);
				linkedFields = StringUtil.split(temp.substring(index + 1), "/",
						"=");
				if (linkedFields == null || linkedFields[0].length != 2) {
					log.error((new StringBuilder(
							"could not find son table in command: ")).append(
							commandString).toString());
					throw new ActionConfigurationException((new StringBuilder(
							"command format error: ")).append(commandString)
							.toString());
				}
			}
			String[] unitIds = StringUtil.split(command[1], "/");
			if (Checker.isEmpty(tableName) || Checker.isEmpty(unitIds)) {
				log
						.error("invaild tables config: tableName or unitId is empty");
				throw new ActionConfigurationException(
						(new StringBuilder(
								"invaild tables config: tableName or unitId is empty: "))
								.append(commandString).toString());
			}
			Map<String, String> values = null;
			if (command.length > 2)
				values = StringUtil.split2Map(command[2], "/", "=");
			Table table = new Table(domain, tableName);
			loadTable(ac, table, unitIds, values, sonTableName, linkedFields);
			tables.add(table);
		}

		return tables;
	}

	private static void loadTable(ActionContext ac, Table table,
			String unitIds[], Map values, String sonTableName,
			String linkedFields[][]) {
		UnitComponent unit = UnitFactory.getUnitWithoutClone(table.getDomain(),
				unitIds[0]);
		Request2SessionExpression.resolve(ac, unit.getDataExpression());
		table.setUnitId(unitIds[0]);
		String operations[] = ac.getRequestParameters(UnitUtil
				.getOperator(unitIds[0]));
		if (Checker.isEmpty(operations)) {
			log.warn((new StringBuilder("No unit operator found: ")).append(
					table.getDomain()).append("/").append(unitIds[0]).append(
					", MappingTable is NULL or UnitShowMode is scan!")
					.toString());
			return;
		}
		TableMeta meta = TableMetaFactory.getTableMeta(table.getDomain(), table
				.getTableName());
		for (int i = 0; i < operations.length; i++)
			if (Operator.INSERT.equals(operations[i])) {
				InsertRow row = (InsertRow) table.addInsertRow();
				row.setRowIndex(i);
				setInsertionRow(ac, i, meta, row, unitIds, values);
			} else if (Operator.UPDATE.equals(operations[i])) {
				UpdateRow row = (UpdateRow) table.addUpdateRow();
				row.setRowIndex(i);
				setUpdateRow(ac, i, meta, row, unitIds, values);
			} else if (Operator.DELETE.equals(operations[i])) {
				DeleteRow row = (DeleteRow) table.addDeleteRow();
				row.setRowIndex(i);
				row.setSonTableName(sonTableName);
				row.setLinkedFields(linkedFields);
				setDeleteRow(ac, i, meta, row, unitIds);
			}

		orderRows(table);
	}

	private static void setInsertionRow(ActionContext ac, int i,
			TableMeta meta, ColumnRow row, String unitIds[], Map values) {
		putColumns(ac, i, meta, row, unitIds, values);
	}

	private static void setUpdateRow(ActionContext ac, int i, TableMeta meta,
			AbstractColumnRow row, String unitIds[], Map values) {
		putColumns(ac, i, meta, row, unitIds, values);
		putPrimaryKeys(ac, i, meta, row, unitIds);
		putVersion(ac, i, meta, row, unitIds);
	}

	private static void setDeleteRow(ActionContext ac, int i, TableMeta meta,
			AbstractColumnRow row, String unitIds[]) {
		putPrimaryKeys(ac, i, meta, row, unitIds);
		putVersion(ac, i, meta, row, unitIds);
	}

	private static void putVersion(ActionContext ac, int i, TableMeta meta,
			AbstractColumnRow row, String unitIds[]) {
		Column column = meta.getVersionColumn();
		if (column != null) {
			String name = column.getName();
			String value = ac.getRequestParameter(i, (new StringBuilder(String
					.valueOf(unitIds[0]))).append(".").append(name)
					.append(".v").toString());
			row.setVersionColumnValue(value);
		}
	}

	private static void putPrimaryKeys(ActionContext ac, int i, TableMeta meta,
			ColumnRow row, String unitIds[]) {
		List columns = meta.getPrimaryKey().getColumns();
		for (int j = 0; j < columns.size(); j++) {
			Column column = (Column) columns.get(j);
			String name = column.getName();
			String value = ac.getRequestParameter(i, (new StringBuilder(String
					.valueOf(unitIds[0]))).append(".").append(name)
					.append(".k").toString());
			if (value != null)
				row.setPrimaryKey(name, column.formatInput(value));
		}

	}

	private static void putColumns(ActionContext ac, int i, TableMeta meta,
			ColumnRow row, String unitIds[], Map values) {
		List<Column> columns = meta.getColumns();
		for (int j = 0; j < columns.size(); j++) {
			Column column = columns.get(j);
			String name = column.getName();
			String value = getValue(ac, i, name, unitIds, values);
			row.set(name, column.formatInput(value));
		}

	}

	private static String getValue(ActionContext ac, int index, String name,
			String unitIds[], Map values) {
		if (values != null) {
			String customKey = (String) values.get(name);
			if (!Checker.isEmpty(customKey))
				return ac.getRequestParameter(customKey);
		}
		for (int i = 0; i < unitIds.length; i++) {
			String value = ac.getRequestParameter(index, (new StringBuilder(
					String.valueOf(unitIds[i]))).append(".").append(name)
					.toString());
			if (value != null)
				return value;
		}

		return null;
	}

	/**
	 * 行数据排序，将删除行置前
	 * 
	 * @param table
	 */
	private static void orderRows(Table table) {
		List<ColumnRow> result = new ArrayList<ColumnRow>();
		List<ColumnRow> rows = table.getRows();
		for (int i = 0; i < rows.size(); i++) {
			ColumnRow row = rows.get(i);
			if (row.isDeleteRow())
				result.add(0, row);
			else
				result.add(row);
		}

		rows.clear();
		for (int i = 0; i < result.size(); i++) {
			rows.add(result.get(i));
		}
	}
}
